#include "../import/head.h"
#include "net_udp.h"
#include "../import/import.h"
#include "../data_struct/head.h"
#include "../global/head.h"
#include "../macro/head.h"
#include "../msg/head.h"

////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_sgsj
{

    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    net_udp::net_udp()
    {
    }

    net_udp::~net_udp()
    {
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // net ret msg proc

    int net_udp::proc( xos::i_msg * pMsg )
    {
        int ret = 0;

        int nMsg = pMsg->get_int( 0, 0 );

        switch( nMsg )
        {
            // 
            // udp
            // 
        case xos_aio::i_aio::AIO_UDP_INIT_RET:
            {
                ret = on_udp_init( pMsg );
            }
            break;
        case xos_aio::i_aio::AIO_UDP_RECV_RET:
            {
                ret = on_udp_recv( pMsg );
            }
            break;
        case xos_aio::i_aio::AIO_UDP_SEND_RET:
            {
                ret = on_udp_send( pMsg );
            }
            break;
        case xos_aio::i_aio::AIO_UDP_CLOSE_HANDLE_RET:
            {
                ret = on_udp_close( pMsg );
            }
            break;
        default:
            {
                ret = 1;
            }
            break;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // udp opt

    // 
    // m_bData[0] : true or false for result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::udp_init( udp * pUdp )
    {
        int ret = 0;

		session * pSession = pUdp->m_pSession;
		xos::i_msg * pMsg = 0;
		
        if( ( 0 == ret ) && ( g_pSysData->m_bQuiting || pSession->m_bQuiting ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pXos->create( xos::i_xos::XOS_OBJ_MSG, ( void ** )&pMsg );
        }

        if( 0 == ret )
        {
            pMsg->set_int( 0, xos_aio::i_aio::AIO_UDP_INIT );
            pMsg->set_str( 1, pUdp->m_szIp );
            pMsg->set_int( 1, pUdp->m_nPort );
            pMsg->set_void( 0, pUdp );
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pAio->post_request( pMsg );
            pMsg = 0;
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[3] : recv len
    // m_lpBuf[0] : recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::udp_post_recv( udp * pUdp )
    {
        int ret = 0;

		session * pSession = pUdp->m_pSession;
        xos::i_msg * pMsg = 0;
        xos::i_buf * pBuf = 0;
        data * pD = 0;

        if( ( 0 == ret ) && ( g_pSysData->m_bQuiting || pSession->m_bQuiting ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pXos->create( xos::i_xos::XOS_OBJ_MSG, ( void ** )&pMsg );
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pXos->create( xos::i_xos::XOS_OBJ_BUF, ( void ** )&pBuf );
        }

        if( 0 == ret )
        {
            pD = g_pSysData->m_pPool->m_data_pool.GetItem();
            pD->init();
            pD->m_pBuf = pBuf;
            pD->m_pUdp = pUdp;
        }

        if( 0 == ret )
        {
            pMsg->set_int( 0, xos_aio::i_aio::AIO_UDP_RECV );
            pMsg->set_buf( 0, pBuf );
            pMsg->set_void( 0, pD );
            pMsg->set_void( 1, pUdp->m_pAioKey );
            pBuf = 0;
            pD = 0;
        }

        if( 0 == ret )
        {
            pUdp->m_nPostRecvNum++;
            ret = g_pSysData->m_os.m_pAio->post_request( pMsg );
            pMsg = 0;
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[4] : send len
    // m_lpBuf[0] : send buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::udp_post_send( data * pData )
    {
        int ret = 0;

        udp * pUdp = pData->m_pUdp;
		session * pSession = pUdp->m_pSession;
        xos::i_msg * pMsg = 0;

        if( ( 0 == ret ) && ( g_pSysData->m_bQuiting || pSession->m_bQuiting ) )
        {
            pData->release();
            pData = 0;
            ret = 1;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pXos->create( xos::i_xos::XOS_OBJ_MSG, ( void ** )&pMsg );
        }

        if( 0 == ret )
        {
            pMsg->set_int( 0, xos_aio::i_aio::AIO_UDP_SEND );
            pMsg->set_str( 2, pData->m_szIp );
            pMsg->set_int( 2, pData->m_nPort );
            pMsg->set_buf( 0, pData->m_pBuf );
            pMsg->set_void( 0, pData );
            pMsg->set_void( 1, pUdp->m_pAioKey );
        }

        if( 0 == ret )
        {
            pUdp->m_nPostSendNum++;
            ret = g_pSysData->m_os.m_pAio->post_request( pMsg );
            pMsg = 0;
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::udp_post_close( udp * pUdp )
    {
        int ret = 0;

		session * pSession = pUdp->m_pSession;
        xos::i_msg * pMsg = 0;

        if( ( 0 == ret ) && pSession->m_bQuiting )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_os.m_pXos->create( xos::i_xos::XOS_OBJ_MSG, ( void ** )&pMsg );
        }

        if( 0 == ret )
        {
            pMsg->set_int( 0, xos_aio::i_aio::AIO_UDP_CLOSE_HANDLE );
            pMsg->set_void( 0, pUdp );
            pMsg->set_void( 1, pUdp->m_pAioKey );
        }

        if( 0 == ret )
        {
			pSession->m_bQuiting = true;
            ret = g_pSysData->m_os.m_pAio->post_request( pMsg );
            pMsg = 0;
        }

        return ret;
    }

    int net_udp::udp_close_test( udp * pUdp )
    {
        int ret = 0;

		session * pSession = pUdp->m_pSession;

        if( ( 0 == ret ) && !pSession->m_bQuiting && !pSession->m_bNeedClose && ( 0 == pUdp->m_nPostRecvNum ) && ( 0 == pUdp->m_nPostSendNum ) )
        {
			pSession->m_bNeedClose = true;
			data * p = g_pSysData->m_pPool->m_data_pool.GetItem();
			p->init();
			p->m_nMsg = MSG_UDP_NEED_CLOSE;
			p->m_pUdp = pUdp;
			g_pSysData->notify(p);
			p = 0;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // udp

    // 
    // m_bData[0] : true or false for result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::on_udp_init( xos::i_msg * pMsg )
    {
        int ret = 0;

        udp * pUdp = ( udp * )pMsg->get_void( 0, 0 );
        void * pAioKey = pMsg->get_void( 1, 0 );
        bool bRet = pMsg->get_bool( 0, 0 );
        session * pSession = pUdp->m_pSession;

        if( bRet )
        {
            pMsg->get_str( 1, pUdp->m_szIp, sizeof( pUdp->m_szIp ), 0 );
            pUdp->m_nPort = pMsg->get_int( 1, 0 );
            g_pSysData->m_pPool->m_session_list.push_back( pSession );
            pUdp->m_pAioKey = pAioKey;
        }

        {
            data * p = g_pSysData->m_pPool->m_data_pool.GetItem();
            p->init();
            p->m_nMsg = MSG_UDP_INIT;
            p->m_bSuccess = bRet;
            p->m_pUdp = pUdp;
            g_pSysData->notify( p );
            p = 0;
        }

        while( bRet && !g_pSysData->m_bQuiting && !pSession->m_bQuiting && ( pUdp->m_nPostRecvNum < g_pSysData->m_config.tcp_max_post_recv ) )
        {
            udp_post_recv( pUdp );
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[3] : recv len
    // m_lpBuf[0] : recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::on_udp_recv( xos::i_msg * pMsg )
    {
        int ret = 0;

        data * pData = ( data * )pMsg->get_void( 0, 0 );
        udp * pUdp = pData->m_pUdp;
		session * pSession = pUdp->m_pSession;
        bool bRet = pMsg->get_bool( 0, 0 );
        int nLen = pMsg->get_int( 3, 0 );

        if( bRet )
        {
            pMsg->get_str( 2, pData->m_szIp, sizeof( pData->m_szIp ), 0 );
            pData->m_nPort = pMsg->get_int( 2, 0 );
            pData->m_pBuf->set_len( nLen );
			pSession->net_timeout_s = 0;
        }

		{
            pData->m_nMsg = MSG_UDP_RECV;
            pData->m_bSuccess = bRet;
            g_pSysData->notify( pData );
            pData = 0;
        }

        while( bRet && !g_pSysData->m_bQuiting && !pSession->m_bQuiting && ( pUdp->m_nPostRecvNum < g_pSysData->m_config.tcp_max_post_recv ) )
        {
            udp_post_recv( pUdp );
        }

        udp_close_test( pUdp );

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[4] : send len
    // m_lpBuf[0] : send buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::on_udp_send( xos::i_msg * pMsg )
    {
        int ret = 0;

        data * pData = ( data * )pMsg->get_void( 0, 0 );
        udp * pUdp = pData->m_pUdp;
		session * pSession = pUdp->m_pSession;
        bool bRet = pMsg->get_bool( 0, 0 );
		
        {
            pData->m_nMsg = MSG_UDP_SEND;
            pData->m_bSuccess = bRet;
            g_pSysData->notify( pData );
            pData = 0;
        }

        udp_close_test( pUdp );

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_udp::on_udp_close( xos::i_msg * pMsg )
    {
        int ret = 0;

        udp * pUdp = ( udp * )pMsg->get_void( 0, 0 );
		session * pSession = pUdp->m_pSession;
        bool bRet = pMsg->get_bool( 0, 0 );

        g_pSysData->m_pPool->m_session_list.remove( pSession );
        
        {
            data * p = g_pSysData->m_pPool->m_data_pool.GetItem();
            p->init();
            p->m_nMsg = MSG_UDP_CLOSE;
            p->m_bSuccess = bRet;
            p->m_pUdp = pUdp;
            g_pSysData->notify( p );
            p = 0;
        }

        if( pSession->m_bQuiting && ( 0 == g_pSysData->m_pPool->m_session_list.size() ) )
        {
            data * p = g_pSysData->m_pPool->m_data_pool.GetItem();
            p->init();
            p->m_nMsg = MSG_NET_STOPPED;
            g_pSysData->notify( p );
            p = 0;
        }

        return ret;
    }

} // xos_sgsj
